import logging
import time
import types

from urllib2 import urlopen, URLError

from threading import Thread

from constants import Enumeration,Status,READSIZE



class DownloaderFactory (object):


    def __init__ (self):
        self.__downloadThreads = [ ]
 
    def createDownloadThread(self,url,file):
        d = Downloader(url,file)
        d.start()
        self.__downloadThreads.append(d)
        return d

    def getDownloadThreads(self):
        return self.__downloadThreads
    

    def __str__(self):
        pass


class Downloader (Thread):


    def __init__(self,url,file):
        Thread.__init__(self)
        self.__url = url
        self.__file = file
        self.__fileSize = 0
        self.__downloadedBytes = 0
        self.__connection = None
        self.__status = Status.Starting
        self.__start = None
        self.__tickTime = None
        self.__lastChunkTime = None
        self.__chunks = 0

    def run (self):
        try:
            self.__start = time.time()
            self.__lastChunkTime = self.__start
            if type(self.__url) == types.StringType:
                self.__connection = urlopen(self.__url)
            else:
                self.__connection = self.__url
                self.__url = self.__connection.geturl()
            self.status = Status.Downloading
            headers = self.__connection.info()
            self.__fileSize = int(headers.getheader('Content-Length'))

        except URLError,e:
            print 'logging error: %s' % str(e)
            self.__status = Status.Error

        while not self.__status == Status.Finished and \
                not self.__status == Status.Error and \
                not self.__status == Status.Stopped: 
            self.__readChunk()


    def __readChunk(self):
        self.__chunks += 1
        t = time.time()
        if self.__chunks % 100 == 0 or self.__chunks == 0:
            self.__tickTime = t - self.__lastChunkTime 
            self.__lastChunkTime = t
        chunk = self.__connection.read(READSIZE)
        self.__downloadedBytes += len(chunk)
        self.__file.write(chunk)
        if self.__downloadedBytes == self.__fileSize:
            self.__status = Status.Finished
            self.__file.close()
            self.__connection.close()
            
        
    def stopDownload(self):
        self.__status = Status.Stopped

    def getProgress(self):
        percent = float(self.__downloadedBytes)/float(self.__fileSize)
        return round(100.0*percent,2)

    def getStatus(self):
        return self.__status

    def getUrl(self):
        return self.__url
    
    def getDownloadedBytes (self):
        return self.__downloadedBytes

    def getElapsedTime(self):
        return time.time()-self.__start

    def getRemainingBytes (self):
        return self.__fileSize-self.__downloadedBytes
        
    def getEstimatedTime(self):
        speed = self.getSpeed()
        if speed != 0:
            return float(self.getRemainingBytes()/1024)/self.getSpeed()
        else:
            return -1

    def getSpeed(self):
        if self.__tickTime is not None:
            return (float(READSIZE*100)/1024)/self.__tickTime
        return 0

    def info(self):
        toString = "File %s: Size: %s \n" % (self.getUrl(),(self.__fileSize/8)/1024)
        toString += "Downloaded: %d Speed: %f\n" %((self.__downloadedBytes/8/1024), self.getSpeed())
        toString += "Progress: %f Status: %d\n" % (self.getProgress(),self.__status)
        toString += "Elapsed Time: %f Estimated Time: %f" % (self.getElapsedTime(),self.getEstimatedTime())
        return toString
    
    
